/*
 * @Author: 彭林
 * @Date: 2020-12-25 11:46:41
 * @LastEditTime: 2021-07-15 08:52:12
 * @LastEditors: 彭林
 * @Description:
 * @FilePath: /saas-app/app/service/course.go
 */
package service

import (
	"errors"
	"fmt"
	"saas-app/app/dao"
	"saas-app/app/define"
	"saas-app/app/model"
	"sync"

	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/util/gconv"
)

type CourseRepository interface {
	GetCourseList(params *define.CourseParams) (courseList []map[string]interface{}, total int)
	CheckCourse(courseList []*define.PaikeParam) []*define.PaikeParam
	AddCourse(courseList []*define.PaikeParam) error
	CheckCourseFunc(course *define.PaikeParam) *define.PaikeParam
}

type course struct{}

func CourseService() CourseRepository {
	return &course{}
}

func (c course) GetCourseList(params *define.CourseParams) ([]map[string]interface{}, int) {

	db := dao.Course.Where("course.school_id = ?", params.SchoolId).Where("course.campus_id = ?", params.CampusId)

	if params.StartTime > 0 && params.EndTime > 0 && params.EndTime > params.StartTime {
		db = db.Where("course.start_time >= ?", gtime.New(params.StartTime*1000))
		db = db.Where("course.start_time <= ?", gtime.New(params.EndTime*1000))
	}

	if params.ClassId > 0 {
		db = db.Where("course.class_id = ?", params.ClassId)
	}

	total, err := db.FindCount()

	if err != nil {
		panic(err)
	}

	db = db.LeftJoin("classes", "course.class_id = classes.id")
	db = db.LeftJoin("subject", "course.subject_id = subject.id")
	db = db.LeftJoin("school_user", "course.teacher_id = school_user.id")

	if params.Page > 0 && params.Limit > 0 {
		db = db.Offset((params.Page - 1) * params.Limit).Limit(params.Limit)
	}

	result, err := db.Fields("classes.class_name", "course.*", "school_user.teacher_name", "subject.subject_name").FindAll()

	if err != nil {
		panic(err)
	}

	courseList := result.List()

	for _, v := range courseList {
		start := gtime.New(v["start_time"].(string)).Timestamp()
		end := gtime.New(v["end_time"].(string)).Timestamp()
		now := int64(gtime.Timestamp())

		if start > now {
			v["status"] = 1
		}

		if start < now && end >= now {
			v["status"] = 2
		}

		if end < now {
			v["status"] = 3
		}
	}

	return courseList, total
}

func (c course) CheckCourse(courseList []*define.PaikeParam) []*define.PaikeParam {
	var wg sync.WaitGroup
	for _, v := range courseList {
		wg.Add(1)
		go func(v *define.PaikeParam) {
			CourseService().CheckCourseFunc(v)
			wg.Done()
		}(v)
	}
	wg.Wait()
	return courseList
}

func (c course) AddCourse(courseList []*define.PaikeParam) error {

	tx, err := g.DB().Begin()

	if err != nil {
		panic(err)
	}

	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	for _, v := range courseList {
		err = c.addCourseFunc(v)
	}

	if err != nil {
		panic(err)
	}

	return err
}

func (c course) CheckCourseFunc(course *define.PaikeParam) *define.PaikeParam {

	endTime := course.StartTime + course.Len*60000

	db := dao.Course.Where("start_time <= ?", endTime).Where("end_time >= ?", course.StartTime)

	if course.ClassID > 0 {
		cx, _ := db.Where("class_id = ?", course.ClassID).FindOne()
		if cx != nil {
			course.Conflict = "class"
			return course
		}
	}

	if course.TeacherID > 0 {

		cx, _ := db.Where("teacher_id = ?", course.TeacherID).FindOne()
		if cx != nil {
			course.Conflict = "teacher"
			return course
		}
	}

	if course.ClassroomID > 0 {
		cx, _ := db.Where("classroom_id = ?", course.ClassroomID).FindOne()
		if cx != nil {
			course.Conflict = "classroom"
			return course
		}
	}

	return course
}

func (c course) addCourseFunc(course *define.PaikeParam) error {

	var cmodel *model.Course
	if err := gconv.Struct(course, &cmodel); err != nil {
		return err
	}

	cmodel.CourseType = "1"
	cmodel.StartTime = gtime.New(course.StartTime)
	cmodel.StartTime = gtime.New(course.StartTime)
	cmodel.EndTime = gtime.New(cmodel.StartTime.Timestamp() + int64(cmodel.Len)*60)

	if re, err := dao.Course.Save(cmodel); err != nil {
		return err
	} else {
		if lastId, err := re.LastInsertId(); err != nil {
			return errors.New("创建失败")
		} else {
			memberListParams := define.ClassMemeberListParams{}
			memberListParams.ClassId = fmt.Sprint(cmodel.ClassId)
			memberListParams.Status = "1"
			memberList, _ := ClassMemberService().GetClassMemeberList(&memberListParams)

			if cmodel.CourseType == "1" && memberList != nil {
				for _, v := range memberList {
					var courseMember model.CourseMember
					courseMember.CampusId = cmodel.CampusId
					courseMember.SchoolId = cmodel.SchoolId
					courseMember.StudentId = v["student_id"].(uint)
					courseMember.CourseId = uint(lastId)
					CourseMemberService().CreateCourseMember(&courseMember)
				}
			}
			return nil
		}
	}
}
